/* Copyright 2007-2008 dnAnalytics Project.
 *
 * Contributors to this file:
 * Patrick van der Velde
 * Marcus Cuda
 * Jurgen Van Gael
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this 
 *   list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * * Neither the name of the dnAnalytics Project nor the names of its contributors
 *   may be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using dnAnalytics.Math;
using dnAnalytics.Properties;

namespace dnAnalytics.LinearAlgebra
{
    /// <summary>
    /// Defines the base class for <c>Vector</c> classes.
    /// </summary>
    [Serializable]
    public abstract class Vector : IFormattable, IEnumerable<double>, ICloneable, IEquatable<Vector>
    {
        private int mCount;

        /// <summary>
        /// Constructs a <strong>Vector</strong> with the given size.
        /// </summary>
        /// <param name="size">The size of the <strong>Vector</strong> to construct.</param>
        /// <exception cref="ArgumentException">If <paramref name="size"/> is less than one.</exception>
        protected Vector(int size)
        {
            if (size < 1)
            {
                throw new ArgumentException(Resources.NotPositive, "size");
            }
            mCount = size;
        }

        /// <summary>
        /// The number of elements in the vector.
        /// </summary>
        public int Count
        {
            get { return mCount; }
        }

        /// <summary>Gets or sets the value at the given <paramref name="index"/>.</summary>
        /// <param name="index">The index of the value to get or set.</param>
        /// <returns>The value of the vector at the given <paramref name="index"/>.</returns> 
        /// <exception cref="IndexOutOfRangeException">If <paramref name="index"/> is negative or 
        /// greater than the size of the vector.</exception>
        public abstract double this[int index] { get; set; }

        #region System.Object overrides

        /// <summary>
        /// Compares two vectors for equality by checking that corresponding vector entries are exactly equal.
        /// </summary>
        public override bool Equals(object obj)
        {
            return Equals(obj as Vector);
        }

        /// <summary>
        /// Compares two vectors for equality by checking that corresponding vector entries are exactly equal.
        /// </summary>
        public bool Equals(Vector other)
        {
            // Reject equality when the argument is null or has a different length.
            if (other == null)
            {
                return false;
            }
            if (Count != other.Count)
            {
                return false;
            }

            // Accept if the argument is the same object as this.
            if (ReferenceEquals(this, other))
            {
                return true;
            }

            // If all else fails, perform element wise comparison.
            for (int i = 0; i < Count; i++)
            {
                if (this[i] != other[i])
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Computes a hash for the vector based on 20 entries using the standard .NET hash computation for double arrays.
        /// </summary>
        public override int GetHashCode()
        {
            int hashNum = System.Math.Min(Count, 20);
            long hash = 0;
            for (int i = 0; i < hashNum; i++)
            {
                hash ^= BitConverter.DoubleToInt64Bits(this[i]);
            }
            return BitConverter.ToInt32(BitConverter.GetBytes(hash), 4);
        }

        #endregion

        #region ICloneable Members

        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion

        #region IEnumerable<KeyValuePair<int,double>> Members


        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        /// <remarks>For sparse vectors, <see cref="GetIndexedEnumerator"/> will perform better.</remarks>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerator<double> GetEnumerator()
        {
            for (int i = 0; i < Count; i++)
            {
                yield return this[i];
            }
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> that contains the position and value of the element.
        /// </summary>
        /// <returns>An <see cref="IEnumerator{T}"/> over this vector that contains the position and value of each
        /// non-zero element.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the element index and the value 
        /// being the value of the element at that index. For sparse vectors, the enumerator will exclude all elements
        /// with a zero value.</remarks>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerable<KeyValuePair<int, double>> GetIndexedEnumerator()
        {
            for (int i = 0; i < Count; i++)
            {
                yield return new KeyValuePair<int, double>(i, this[i]);
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region IFormattable Members

        /// Returns a <seealso cref="string"/> representation of this vector using
        /// the given format and <seealso cref="IFormatProvider"/>.
        /// <param name="format">The format to use.</param>
        /// <param name="formatProvider">The format provider to use.</param>       
        /// <returns>The string representation of the value of <strong>this</strong> instance as specified by format and provider.</returns>
        public virtual string ToString(string format, IFormatProvider formatProvider)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Count; i++)
            {
                sb.Append(this[i].ToString(format, formatProvider));
                if (i != Count - 1)
                {
                    sb.Append(", ");
                }
            }
            return sb.ToString();
        }

        #endregion

        /// <summary>Calculates the infinity norm of this vector.</summary>
        /// <returns>The infinity norm of this vector.</returns>  
        public virtual double InfinityNorm()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret = System.Math.Max(ret, System.Math.Abs(this[i]));
            }
            return ret;
        }

        /// <summary>
        /// Computes the P-Norm of the vector.
        /// </summary>
        /// <param name="pValue">The norm to compute.</param>
        /// <returns>Returns the value of the P-norm.</returns>
        public virtual double PNorm(int pValue)
        {
            if (pValue < 1)
            {
                throw new ArgumentOutOfRangeException("pValue", Resources.NotPositive);
            }
            if (pValue == 1)
            {
                double sum = 0.0;
                for (int i = 0; i < Count; i++)
                {
                    sum += System.Math.Abs(this[i]);
                }
                return sum;
            }
            else
            {
                double sum = 0.0;
                for (int i = 0; i < Count; i++)
                {
                    sum += System.Math.Pow(System.Math.Abs(this[i]), pValue);
                }
                return System.Math.Pow(sum, 1.0 / pValue);
            }
        }

        /// <summary>
        /// Normalizes a vector.
        /// </summary>
        /// <param name="pValue">The norm under which to normalize the vector under.</param>
        /// <returns>A normalized version of the vector.</returns>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="pValue"/> is smaller than 1.</exception>
        public virtual Vector Normalize(int pValue)
        {
            if (pValue < 1)
            {
                throw new ArgumentOutOfRangeException("pValue", Resources.NotPositive);
            }

            Vector ret = this.Clone();
            double norm = this.PNorm(pValue);
            ret.Divide(norm);
            return ret;
        }

        /// <summary>
        /// Returns the value of the absolute maximum element.
        /// </summary>
        /// <returns>The value of the absolute maximum element.</returns>
        public virtual double AbsoluteMaximum()
        {
            return System.Math.Abs(this[AbsoluteMaximumIndex()]);
        }

        /// <summary>
        /// Returns the index of the absolute maximum element.
        /// </summary>
        /// <returns>The index of absolute maximum element.</returns>        
        public virtual int AbsoluteMaximumIndex()
        {
            int index = 0;
            double max = System.Math.Abs(this[index]);
            for (int i = 1; i < Count; i++)
            {
                double test = System.Math.Abs(this[i]);
                if (test > max)
                {
                    index = i;
                    max = test;
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of the absolute minimum element.
        /// </summary>
        /// <returns>The value of the absolute minimum element.</returns>
        public virtual double AbsoluteMinimum()
        {
            return System.Math.Abs(this[AbsoluteMinimumIndex()]);
        }

        /// <summary>
        /// Returns the index of the absolute minimum element.
        /// </summary>
        /// <returns>The index of absolute minimum element.</returns>        
        public virtual int AbsoluteMinimumIndex()
        {
            int index = 0;
            double min = System.Math.Abs(this[index]);
            for (int i = 1; i < Count; i++)
            {
                double test = System.Math.Abs(this[i]);
                if (test < min)
                {
                    index = i;
                    min = test;
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of maximum element.
        /// </summary>
        /// <returns>The value of maximum element.</returns>        
        public virtual double Maximum()
        {
            return this[MaximumIndex()];
        }

        /// <summary>
        /// Returns the index of the absolute maximum element.
        /// </summary>
        /// <returns>The index of absolute maximum element.</returns>          
        public virtual int MaximumIndex()
        {
            int index = 0;
            double max = this[0];
            for (int i = 1; i < Count; i++)
            {
                if (max < this[i])
                {
                    index = i;
                    max = this[i];
                }
            }
            return index;
        }

        /// <summary>
        /// Returns the value of the minimum element.
        /// </summary>
        /// <returns>The value of the minimum element.</returns>
        public virtual double Minimum()
        {
            return this[MinimumIndex()];
        }

        /// <summary>
        /// Returns the index of the minimum element.
        /// </summary>
        /// <returns>The index of minimum element.</returns>  
        public virtual int MinimumIndex()
        {
            int index = 0;
            double min = this[0];
            for (int i = 1; i < Count; i++)
            {
                if (min > this[i])
                {
                    index = i;
                    min = this[i];
                }
            }
            return index;
        }

        /// <summary>
        /// Sets the each element to zero.
        /// </summary>
        public virtual void Clear()
        {
            for (int i = 0; i < Count; i++)
            {
                this[i] = 0;
            }
        }

        /// <summary>
        /// Copies the values of this vector into the target vector.
        /// </summary>
        /// <param name="target">The vector to copy elements into.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="target"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <paramref name="target"/> is not the same size as this vector.</exception>
        public virtual void CopyTo(Vector target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            if (Count != target.Count)
            {
                throw new NotConformableException("target", Resources.ParameterNotConformable);
            }
            if (ReferenceEquals(this, target))
            {
                return;
            }

            for (int i = 0; i < Count; i++)
            {
                target[i] = this[i];
            }
        }

        /// <summary>
        /// Copies the requested elements from this vector to another.
        /// </summary>
        /// <param name="destination">The vector to copy the elements to.</param>
        /// <param name="offset">The element to start copying from.</param>
        /// <param name="destinationOffset">The element to start copying to.</param>
        /// <param name="count">The number of elements to copy.</param>
        public virtual void CopyTo(Vector destination, int offset, int destinationOffset, int count )
        {
            if(destination == null)
            {
                throw new ArgumentNullException("destination");
            }
            if( offset >= mCount)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (offset+count > mCount)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            if (destinationOffset >= destination.Count)
            {
                throw new ArgumentOutOfRangeException("destinationOffset");
            }

            if (destinationOffset + count > destination.Count)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            if (ReferenceEquals(this, destination))
            {
                Vector tmp = destination.CreateVector(destination.Count);
                CopyTo(tmp, offset, destinationOffset, count);
                tmp.CopyTo(destination);
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    destination[destinationOffset + i] = this[offset + i];
                }
            }
        }

        ///<summary>Computes the dot product of this vector with itself.</summary>
        ///<returns>The dot product of this vector and itself.</returns>
        public virtual double DotProduct()
        {
            return DotProduct(this);
        }

        /// <summary>Computes the dot product of this vector with another.</summary>
        /// <param name="other">The vector to compute the dot product with.</param>
        /// <returns>The dot product of this vector and other.</returns>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If this vector  and other are not the same size.</exception>
        public virtual double DotProduct(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            double result = 0;
            for (int i = 0; i < Count; i++)
            {
                result += this[i]*other[i];
            }
            return result;
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> over the specified elements.
        /// </summary>
        /// <param name="index">The element to start copying from.</param>
        /// <param name="length">The number of elements to enumerate over.</param>
        /// <returns>An <see cref="IEnumerator{T}"/> over a range of this vector.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> or <paramref name="index"/> + <paramref name="length"/>
        /// is greater than the vector's length. </exception>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the element index and the value 
        /// being the value of the element at that index.</remarks>
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerator<KeyValuePair<int, double>> GetEnumerator(int index, int length)
        {
            if (index > mCount)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            if (index + length > mCount)
            {
                throw new ArgumentOutOfRangeException("length");
            }

            for (int i = index; i < length; i ++)
            {
                yield return new KeyValuePair<int, double>(i, this[i]);
            }
        }

        /// <summary>
        /// Creates a vector containing specified elements.
        /// </summary>
        /// <param name="index">The first element to begin copying from.</param>
        /// <param name="length">The number of elements to copy.</param>
        /// <returns>A vector containing a copy of the specified elements.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><list><item>If <paramref name="index"/> is not positive or
        /// greater than or equal to the size of the vector.</item>
        /// <item>If <paramref name="index"/> + <paramref name="length"/> is greater than or equal to the size of the vector.</item>
        /// </list></exception>
        /// <exception cref="ArgumentException">If <paramref name="length"/> is not positive.</exception>
        public virtual Vector GetSubVector(int index, int length)
        {
            if (index < 0 || index >= Count)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            if (index + length > Count)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            Vector ret = CreateVector(length);
            for (int i = index, j = 0; i < index + length; i ++, j++)
            {
                ret[j] = this[i];
            }
            return ret;
        }

        /// <summary>
        /// Computes the sum of the vector's elements.
        /// </summary>
        /// <returns>The sum of the vector's elements.</returns>
        public virtual double Sum()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret += this[i];
            }
            return ret;
        }

        /// <summary>
        /// Computes the sum of the absolute value of the vector's elements.
        /// </summary>
        /// <returns>The sum of the absolute value of the vector's elements.</returns>
        public virtual double SumMagnitudes()
        {
            double ret = 0;
            for (int i = 0; i < Count; i++)
            {
                ret += System.Math.Abs(this[i]);
            }
            return ret;
        }

        /// <summary>
        /// Returns the data contained in the vector as an array.
        /// </summary>
        /// <returns>The vector's data as an array.</returns>        
        public virtual double[] ToArray()
        {
            double[] ret = new double[Count];
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i] = this[i];
            }
            return ret;
        }

        /// <summary>
        /// Set the values of this vector to the given values.
        /// </summary>
        /// <param name="values">The array containing the values to use.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="values"/> is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If <paramref name="values"/> is not the same size as this vector.</exception>
        public virtual void SetValues(double[] values)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }
            if (values.Length != Count)
            {
                throw new NotConformableException("values", Resources.ArrayParameterNotConformable);
            }
            for (int i = 0; i < values.Length; i++)
            {
                this[i] = values[i];
            }
        }

        /// <summary>
        /// Adds a scalar to each element of the vector.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>
        public virtual void Add(double scalar)
        {
            if (scalar == 0.0)
            {
                return;
            }

            for (int i = 0; i < Count; i++)
            {
                this[i] += scalar;
            }
        }

        /// <summary>
        /// Adds a scalar to each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>
        /// <param name="result">The vector to store the result of the addition.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Add(double scalar, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (Count != result.Count)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }
            CopyTo(result);
            result.Add(scalar);
        }

        /// <summary>
        /// Returns a clone of this vector.
        /// </summary>
        /// <returns>A clone of this vector.</returns>
        /// <remarks>Added as an alternative to the unary addition operator.</remarks>
        public virtual Vector Plus()
        {
            return Clone();
        }

        /// <summary>
        /// Adds another vector to this vector.
        /// </summary>
        /// <param name="other">The vector to add to this one.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void Add(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }
            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }
            for (int i = 0; i < Count; i++)
            {
                this[i] += other[i];
            }
        }

        /// <summary>
        /// Adds another vector to this vector and stores the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to add to this one.</param>
        /// <param name="result">The vector to store the result of the addition.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Add(Vector other, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result");
            }

            if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
            {
                Vector tmp = result.CreateVector(result.Count);
                Add(other, tmp);
                tmp.CopyTo(result);
            }
            else
            {
                CopyTo(result);
                result.Add(other); 
            }
        }

        /// <summary>
        /// Adds a scaled vector to the current vector.
        /// </summary>
        /// <param name="scale">The scale factor with which to multiply the <paramref name="other"/> vector.</param>
        /// <param name="other">The vector that should be scaled and added.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void AddScaledVector(double scale, Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                this[i] += scale * other[i];
            }
        }

        /// <summary>
        /// Adds a scaled vector to the current vector.
        /// </summary>
        /// <param name="scale">The scale factor with which to multiply the <paramref name="other"/> vector.</param>
        /// <param name="other">The vector to add to this one.</param>
        /// <param name="result">The vector to store the result of the addition.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void AddScaledVector(double scale, Vector other, Vector result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] + scale * other[i];
            }
        }

        /// <summary>
        /// Pointwise multiplies this vector with another vector.
        /// </summary>
        /// <param name="other">The vector to pointwise multiply with this one.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <returns>A new vector that is the pointwise multiplication of this vector and <paramref name="other"/>.</returns>
        public virtual Vector PointwiseMultiply(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }
            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            Vector result = CreateVector(Count);
            PointwiseMultiply(other, result);
            return result;
        }

        /// <summary>
        /// Pointwise multiplies this vector with another vector and stores the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to pointwise multiply with this one.</param>
        /// <param name="result">The vector to store the result of the pointwise multiplication.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void PointwiseMultiply(Vector other, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }
            
            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result");
            }

            for (int i = 0; i < Count; i++)
            {
                result[i] = this[i] * other[i];
            }
        }

        /// <summary>
        /// Negates the values of this vector.
        /// </summary>
        public virtual void Negate()
        {
            Multiply(-1);
        }

        /// <summary>
        /// Subtracts a scalar from each element of the vector.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        public virtual void Subtract(double scalar)
        {
            Add(-scalar);
        }

        /// <summary>
        /// Subtracts a scalar from each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        /// <param name="result">The vector to store the result of the subtraction.</param>
        /// <exception cref="ArgumentNullException">If the result vector is <see langword="null" />.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Subtract(double scalar, Vector result)
        {
            Add(-scalar, result);
        }

        /// <summary>
        /// Subtracts another vector from this vector.
        /// </summary>
        /// <param name="other">The vector to subtract from this one.</param>
        /// <exception cref="ArgumentNullException">If the other vector is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        public virtual void Subtract(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }
            if (Count != other.Count)
            {
                throw new NotConformableException("other", Resources.ParameterNotConformable);
            }

            for (int i = 0; i < Count; i++)
            {
                this[i] -= other[i];
            }
        }

        /// <summary>
        /// Subtracts another vector from this vector and stores the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to subtract from this one.</param>
        /// <param name="result">The vector to store the result of the subtraction.</param>
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="other"/> or <paramref name="result"/> is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="other"/> are not the same size.</exception>
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Subtract(Vector other, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (Count != result.Count)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
            {
                Vector tmp = result.CreateVector(result.Count);
                Subtract(other, tmp);
                tmp.CopyTo(result);
            }
            else
            {
                CopyTo(result);
                result.Subtract(other);
            }
        }

        /// <summary>
        /// Divides this vector by scalar.
        /// </summary>
        /// <param name="scalar">The scalar to divide this vector by.</param>
        public virtual void Divide(double scalar)
        {
            Multiply(1.0/scalar);
        }


        /// <summary>
        /// Divides this vector by scalar and store the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to divide this vector by.</param>
        /// <param name="result">The vector to store the result of the division.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Divide(double scalar, Vector result)
        {
            Multiply(1.0/scalar, result);
        }

        /// <summary>
        /// Multiplies this vector by scalar.
        /// </summary>
        /// <param name="scalar">The scalar to multiply this vector with.</param>
        public virtual void Multiply(double scalar)
        {
            if (scalar == 1.0)
            {
                return;
            }
            for (int i = 0; i < Count; i++)
            {
                this[i] *= scalar;
            }
        }

        /// <summary>
        /// Multiplies this vector by scalar and store the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to multiply this vector with.</param>
        /// <param name="result">The vector to store the result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="result"/> is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If this vector and <paramref name="result"/> are not the same size.</exception>
        public virtual void Multiply(double scalar, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (Count != result.Count)
            {
                throw new NotConformableException("result", Resources.ParameterNotConformable);
            }

            CopyTo(result);
            result.Multiply(scalar);
        }

        /// <summary>
        /// Multiplies this vector with another vector (this x other) and returns the resulting <see cref="Matrix"/>.
        /// </summary>
        /// <param name="other">The vector to multiply the vector with.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="other"/> is <see langword="null" />.</exception> 
        public virtual Matrix Multiply(Vector other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            Matrix result = new DenseMatrix(Count, other.Count);
            Multiply(other, result);
            return result;
        }

        /// <summary>
        /// Multiplies this vector with another vector (this x other) and places the result into the result vector.
        /// </summary>
        /// <param name="other">The vector to multiply the vector with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="other"/>  or <paramref name="result"/>  is <see langword="null" />.</exception> 
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception> 
        /// <exception cref="NotConformableException">If result matrix does not have the correct dimensions.</exception>
        public virtual void Multiply(Vector other, Matrix result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (result.Rows != Count || result.Columns != other.Count)
            {
                throw new NotConformableException("result", Resources.ResultMatrixIncorrectDimensions);
            }

            for (int i = 0; i < Count; i++)
            {
                for (int j = 0; j < other.Count; j++)
                {
                    result[i, j] = this[i]*other[j];
                }
            }
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector.
        /// </summary>
        ///<returns>The string representation of this vector as comma separated values.</returns>
        public override string ToString()
        {
            return ToString(null, null);
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector using
        /// the given format.
        /// </summary>
        /// <param name="format">The format to use.</param>
        ///<returns>The string representation of this vector as comma separated values.</returns>
        public virtual string ToString(string format)
        {
            return ToString(format, null);
        }

        /// <summary>
        /// Returns a <seealso cref="string"/> representation of this vector using
        /// the given <seealso cref="IFormatProvider"/>.
        /// </summary>
        /// <param name="formatProvider">The format provider to use.</param>
        ///<returns>The string representation of this vector as comma separated values.</returns>
        public virtual string ToString(IFormatProvider formatProvider)
        {
            return ToString(null, formatProvider);
        }

        /// <summary>
        /// Returns a deep-copy clone of the vector.
        /// </summary>
        /// <returns>A deep-copy clone of the vector.</returns>
        public Vector Clone()
        {
            Vector ret = CreateVector(Count);
            CopyTo(ret);
            return ret;
        }

        /// <summary>
        /// Returns a <strong>Vector</strong> containing the same values of rightSide. 
        /// </summary>
        /// <remarks>This method is included for completeness.</remarks>
        /// <param name="rightSide">The vector to get the values from.</param>
        /// <returns>A vector containing a the same values as <paramref name="rightSide"/>.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Vector operator +(Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            return rightSide.Clone();
        }

        /// <summary>
        /// Adds two <strong>Vectors</strong> together and returns the results.
        /// </summary>
        /// <param name="leftSide">One of the vectors to add.</param>
        /// <param name="rightSide">One of the vectors to add.</param>
        /// <returns>The result of the addition.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Vector operator +(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (leftSide.mCount != rightSide.mCount)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }

            Vector ret = leftSide.Clone();
            ret.Add(rightSide);
            return ret;
        }

        /// <summary>
        /// Negates each element of the vector.
        /// </summary>
        /// <param name="rightSide">The vector to negate.</param>
        /// <returns>A vector containing the negated values.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Vector operator -(Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }

            Vector ret = rightSide.Clone();
            ret.Negate();
            return ret;
        }

        /// <summary>
        /// Subtracts two vectors and returns the results.
        /// </summary>
        /// <param name="leftSide">The vector to subtract from.</param>
        /// <param name="rightSide">The vector to subtract.</param>
        /// <returns>The result of the subtraction.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> are not the same size.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Vector operator -(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            if (leftSide.Count != rightSide.Count)
            {
                throw new NotConformableException(Resources.ParametersNotConformable);
            }
            Vector ret = leftSide.Clone();
            ret.Subtract(rightSide);
            return ret;
        }

        /// <summary>
        /// Divides a <strong>Vector</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to divide.</param>
        /// <param name="rightSide">The constant to divide the vector by.</param>
        /// <returns>The result of the division.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
        public static Vector operator /(Vector leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }

            Vector ret = leftSide.Clone();
            ret.Divide(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <strong>Vector</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The constant to multiply the vector by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Vector operator *(double leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }
            Vector ret = rightSide.Clone();
            ret.Multiply(leftSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <strong>Vector</strong> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The constant to multiply the vector by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <see langword="null" />.</exception>
        public static Vector operator *(Vector leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }
            Vector ret = leftSide.Clone();
            ret.Multiply(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiples two <strong>Vectors</strong>. The first vector is treated as column vector and
        /// the second as row vector.
        /// </summary>
        /// <param name="leftSide">One of the vectors to multiply.</param>
        /// <param name="rightSide">One of the vectors to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <see langword="null" />.</exception>
        public static Matrix operator *(Vector leftSide, Vector rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide");
            }

            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide");
            }
            return leftSide.Multiply(rightSide);
        }

        /// <summary>
        /// Creates a matrix with the given dimensions using the same storage type
        /// as this vector uses.
        /// </summary>
        /// <param name="rows">The number of rows.</param>
        /// <param name="columns">The number of columns.</param>
        /// <returns>A matrix with the given dimensions.</returns>
        public abstract Matrix CreateMatrix(int rows, int columns);

        /// <summary>
        /// Creates a <strong>Vector</strong> of the given size;
        /// </summary>
        /// <param name="size">The size of the <strong>Vector</strong> to create.</param>
        /// <returns>The new <strong>Vector</strong>.</returns>
        protected internal abstract Vector CreateVector(int size);
    }
}
